package net.opentsdb.bean;

import com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.base.Strings;
import com.google.common.io.Files;
import net.opentsdb.core.Const;
import net.opentsdb.utils.Config;
import net.opentsdb.utils.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author zhuzp
 * @time 2020-06-12 09:57
 * @name TableBean
 * @desc 表管理
 **/
public class TableBean {

    private static final Logger LOG = LoggerFactory.getLogger(TableBean.class);
    private static final Charset CHARSET = StandardCharsets.UTF_8;

    private Config config;

    public TableBean(final Config config){
        this.config = config;
        this.table = config.getString("tsd.storage.hbase.data_table");
        this.uidTable = config.getString("tsd.storage.hbase.uid_table");
        this.treeTable = config.getString("tsd.storage.hbase.tree_table");
        this.metaTable = config.getString("tsd.storage.hbase.meta_table");
        this.tagTable = config.getString("tsd.storage.hbase.tag_table");
        initForwards();
    }

    private String table;
    private String uidTable;
    private String treeTable;
    private String metaTable;
    private String tagTable;
    private Map<String, ForwardBean> forwards = new HashMap<>();

    public byte[] getTable() {
        return getTable(null);
    }

    public byte[] getTable(String division) {
        return table.concat(this.formatDate(division)).getBytes(CHARSET);
    }

    public byte[] getUidTable() {
        return uidTable.getBytes(CHARSET);
    }

    public byte[] getTreeTable() {
        return treeTable.getBytes(CHARSET);
    }

    public byte[] getMetaTable() {
        return metaTable.getBytes(CHARSET);
    }

    public byte[] getTagTable() {
        return tagTable.getBytes(CHARSET);
    }

    /**
     * 获取跳转表
     * @param forward
     * @return
     */
    public byte[] getForwardTable(String forward){
        return getForwardTable(forward, null);
    }

    public byte[] getForwardTable(String forward, String division){
        ForwardBean bean = forwards.get(forward);
        if(bean == null){
            return this.getTable();
        }else {
            return bean.getForwardTable().concat(this.formatDate(division)).getBytes();
        }
    }

    public Map<String, ForwardBean> getForwardBeans() {
        return forwards;
    }

    private void initForwards() {
        if(config.isEnableTableForward()){
            String forwardConf = config.getForwardTableConfig();
            if (Strings.isNullOrEmpty(forwardConf)) {
                config.setEnableTableForward(false);
                LOG.error("forward were enabled but forward config is null or empty.");

            }else if (forwardConf.endsWith(".json")) {
                try {
                    forwardConf = Files.toString(new File(forwardConf), Const.UTF8_CHARSET);
                } catch (IOException e) {

                    String sep = File.separator;
                    String fileName = forwardConf.substring(forwardConf.lastIndexOf(sep)+1);
                    String configPath = config.configLocation();
                    String confPath = configPath.substring(0,configPath.lastIndexOf(sep)+1);

                    File forwardConfig = new File(confPath+fileName);

                    if(forwardConfig.exists()){
                        try{
                            forwardConf = Files.toString(new File(confPath+fileName), Const.UTF8_CHARSET);
                        }catch(Exception e1){
                            config.setEnableTableForward(false);
                            LOG.error("Failed to open forward conf file: " + forwardConf, e1);
                        }
                    }else {
                        config.setEnableTableForward(false);
                        LOG.error("Failed to open forward conf file: " + forwardConf, e);
                    }
                }

                if(config.isEnableTableForward()){
                    TypeReference<ArrayList<ForwardBean>> TR_TREE_RULES = new TypeReference<ArrayList<ForwardBean>>() {};
                    List<ForwardBean> forwardBeans = JSON.parseToObject(forwardConf,TR_TREE_RULES);

                    if(forwardBeans != null && forwardBeans.size() > 0){
                        for(ForwardBean bean: forwardBeans){
                            if(!Strings.isNullOrEmpty(bean.getForward())){
                                forwards.put(bean.getForward(), bean);
                            }
                        }
                    }
                }
            }else {
                config.setEnableTableForward(false);
                LOG.error("forward conf end with non json, so set enable.forward fals");
            }

        }
    }

    private String formatDate(String division){

        if(!config.getBoolean("tsd.core.table.month.enable")){
            return "";
        }

        LocalDate localDate;

        if(division != null && division.length() == 6){
            try{
                DateTimeFormatter formatter = new DateTimeFormatterBuilder()
                        .appendPattern("yyyyMM")
                        .parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
                        .toFormatter();
                localDate = LocalDate.parse(division, formatter);
            }catch (Exception e){
                localDate = LocalDate.now();
            }
        }else {
            localDate = LocalDate.now();
        }

        int year = localDate.getYear();
        int month = localDate.getMonthValue();

        if(month < 10){
            return "-".concat(String.valueOf(year)).concat("0").concat(String.valueOf(month));
        }else {
            return "-".concat(String.valueOf(year)).concat(String.valueOf(month));
        }
    }

}
